Skip to content

fix(InputNumber): keep previous value on unparseable input, emit null when cleared#6772

Open
61021 wants to merge 2 commits into
nuxt:v4from
61021:fix/input-number-unparseable
Open

fix(InputNumber): keep previous value on unparseable input, emit null when cleared#6772
61021 wants to merge 2 commits into
nuxt:v4from
61021:fix/input-number-unparseable

Conversation

@61021

@61021 61021 commented Jul 24, 2026

Copy link
Copy Markdown

🔗 Linked issue

Resolves #6743

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

First, a root-cause correction for the issue title: no NaN is ever emitted. Committing unparseable text like . or - (Enter/blur) makes reka-ui's NumberField emit undefined — the reporter's isNaN(v) check reads true because isNaN(undefined) is true, and undefined poisons downstream arithmetic into NaN. Reka's applyInputValue conflates two situations that deserve different handling: a cleared input and non-empty unparseable text both nuke the model to undefined (and destroy the previous value).

Two commits, separable:

1. fix(InputNumber): keep previous value when committing unparseable input — what the reporter asked for ("maybe just revert to the previous value instead?"), matching react-spectrum's behavior. All model updates now flow through onUpdate() — previously the auto-forwarded update:modelValue handler bypassed it entirely in non-.optional mode (and double-emitted in .optional mode). When the committed value is undefined but the input still contains text, the update is dropped; since NumberFieldRoot runs controlled, it restores the last formatted value on its own. Verified in the added test: . + Enter on a model of 5 → no emit, input text back to 5.

2. fix(InputNumber): emit null when cleared to match the declared model type — the typing-soundness half reported by @danekslama in the issue comments: the emit type is number | null (undefined only with the .optional modifier), but clearing leaked undefined at runtime regardless. Clearing now emits null, or undefined with .optional (unchanged). This one is mildly behavior-visible for consumers who relied on the untyped undefined — happy to drop this commit if you'd rather keep it wrapper-compatible, the first commit stands alone.

Tests cover all three paths (unparseable revert / clear → null / clear + .optionalundefined); existing suites and snapshots unchanged (110 tests green, vue-tsc clean).

Upstream note: the revert-on-unparseable behavior arguably belongs in reka-ui's applyInputValue eventually, but the wrapper can't wait on that and needs the null convention regardless — no reka-ui issue exists for it yet, I can file one.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

61021 and others added 2 commits July 24, 2026 19:39
Reka UI's NumberField emits `undefined` for both a cleared input and a
non-empty value that fails to parse (e.g. "." or "-" with Enter/blur),
destroying the previous model value in the second case — reported as
"can return NaN" since `isNaN(undefined)` is true and undefined poisons
arithmetic downstream.

Route all model updates through onUpdate() (the auto-forwarded
update:modelValue handler bypassed it entirely in non-optional mode) and
drop the update when the committed text is non-empty but unparseable:
the controlled NumberFieldRoot then restores the last formatted value on
its own.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…type

The emit type is `number | null` (undefined only with the .optional
modifier), but clearing the field leaked `undefined` at runtime
regardless of the modifier.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@61021
61021 requested a review from benjamincanac as a code owner July 24, 2026 16:41
@github-actions github-actions Bot added the v4 #4488 label Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b7e1dd7e-5e7d-40af-899c-acaf5a235585

📥 Commits

Reviewing files that changed from the base of the PR and between 8897318 and ac3c741.

📒 Files selected for processing (2)
  • src/runtime/components/InputNumber.vue
  • test/components/InputNumber.spec.ts

📝 Walkthrough

Walkthrough

InputNumber now suppresses direct update:modelValue forwarding from the underlying number field. Its update handler distinguishes unparseable text from cleared input, preserving the previous value for invalid text and converting cleared input to null or undefined based on the optional modifier. Tests cover invalid input and both clearing behaviors.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main InputNumber fix for unparseable input and cleared-state handling.
Description check ✅ Passed The description matches the changeset and explains the InputNumber bug fix and test coverage.
Linked Issues check ✅ Passed The PR restores the previous value for unparseable commits, which addresses the core behavior requested in #6743.
Out of Scope Changes check ✅ Passed The changes stay within InputNumber normalization and tests, with no unrelated code or behaviors introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 24, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/@nuxt/ui@6772

commit: ac3c741

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InputNumber can return NaN

1 participant